//
//  ZStreamPrivate.h
//  Part of Z-Way.C library
//
//  Created by Pavel Kulaha.
//  Based on Z-Way source code written by Christian Paetz and Poltorak Serguei
//
//  Copyright (c) 2012 Z-Wave.Me
//  All rights reserved
//  info@z-wave.me
//
//  This source file is subject to the terms and conditions of the
//  Z-Wave.Me Software License Agreement which restricts the manner
//  in which it may be used.
//

#ifndef zstream_private_h
#define zstream_private_h

#include "ZPlatform.h"
#include "ZLog.h"
#include "ZFileOperationsPrivate.h"
#include "ZByteOperationsPrivate.h"

#if defined(__ESP32__)
#include "esp_http_server.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef struct _ZStreamCommonCtx_s
{
    ZWLog log;
} _ZStreamCommonCtx_t;

typedef struct _ZStreamWriteBufferingCtx_s
{
    _ZByteData_t data;
    size_t size;
} _ZStreamWriteBufferingCtx_t;

typedef struct _ZStreamWriteFileCtx_s
{
    _ZStreamCommonCtx_t ctx_common;
    _ZStreamWriteBufferingCtx_t buffering;
    ZW_FILE_HANDLE fd;
} _ZStreamWriteFileCtx_t;

typedef struct _ZStreamRWFileCtx_s
{
    _ZStreamWriteFileCtx_t write;
    size_t offset;
} _ZStreamRWFileCtx_t;

typedef struct _ZStreamWriteRamCtx_s
{
    _ZStreamCommonCtx_t ctx_common;
    _ZByteData_t data;
    size_t block_size;
} _ZStreamWriteRamCtx_t;

typedef struct _ZStreamCtxReaderRam_s
{
    _ZStreamCommonCtx_t ctx_common;
    _ZByteData_t data;
    size_t position;
} _ZStreamCtxReaderRam_t;

typedef struct _ZStreamCtxReaderFile_s
{
    _ZStreamCommonCtx_t ctx_common;
    ZW_FILE_HANDLE fd;
    size_t n;
    size_t position;
} _ZStreamCtxReaderFile_t;

#if defined(__ESP32__)
typedef struct _ZStreamWriteEspCtx_s
{
    _ZStreamCommonCtx_t ctx_common;
    _ZStreamWriteBufferingCtx_t buffering;
    httpd_req_t *req;
} _ZStreamWriteEspCtx_t;
#endif

typedef struct _ZStreamRWRamCtx_s
{
    _ZStreamWriteRamCtx_t write;
} _ZStreamRWRamCtx_t;

typedef struct _ZStreamHttpWriteHeader_s
{
    _ZByteData_t name;
    _ZByteData_t value;
} _ZStreamHttpWriteHeader_t;

typedef struct _ZStreamHttpWriteContent_s
{
    _ZByteData_t content_type;
    _ZStreamHttpWriteHeader_t array[3];
    size_t i;
} _ZStreamHttpWriteContent_t;

typedef struct _ZStreamHttpWriteRamCtx_s
{
    _ZStreamWriteRamCtx_t write;
    _ZStreamHttpWriteContent_t content;
} _ZStreamHttpWriteRamCtx_t;

#if defined(__ESP32__)
typedef struct _ZStreamHttpWriteEspCtx_s
{
    _ZStreamWriteEspCtx_t write;
    _ZStreamHttpWriteContent_t content;
    ZWBOOL empty;
} _ZStreamHttpWriteEspCtx_t;
#endif

typedef struct _ZStreamHttpWriteRamResult_s
{
    _ZStreamHttpWriteContent_t content;
    _ZByteData_t data;
} _ZStreamHttpWriteRamResult_t;

typedef struct _ZStreamReader_s
{
    ZWError (*read_offset)(void *, void *, size_t, size_t);
    ZWError (*read)(void *, void *, size_t);
    ZWError (*seek)(void *, size_t);
    size_t (*size)(void *);
    size_t (*position)(void *);
} _ZStreamReader_t;

typedef struct _ZStreamWriter_s
{
    ZWError (*write)(void *, const void *, size_t);
    ZWError (*allocate)(void *, size_t);
    size_t (*size)(void *);
} _ZStreamWriter_t;

typedef struct _ZStreamRW_s
{
    ZWError (*read_offset)(void *, void *, size_t, size_t);
    
    const _ZStreamWriter_t writer;
} _ZStreamRW_t;

typedef struct _ZStreamHttpWrite_s
{
    void (*set_content_type)(void *, _ZByteData_t *);
    ZWError (*set_header)(void *, _ZStreamHttpWriteHeader_t *);
    
    const _ZStreamWriter_t writer;
} _ZStreamHttpWrite_t;

ZWEXPORT_PRIVATE const _ZStreamWriter_t *_zstream_write_ram(void);
ZWEXPORT_PRIVATE void _zstream_write_ram_init(_ZStreamWriteRamCtx_t *const ctx, const ZWLog log, const size_t block_size);
ZWEXPORT_PRIVATE void _zstream_write_ram_result(_ZStreamWriteRamCtx_t *const ctx, _ZByteData_t *const data);
static inline void _zstream_write_ram_free(_ZStreamWriteRamCtx_t *const ctx)
{
    _zbyte_data_free(&ctx->data);
}
static inline ZWError _zstream_write_ram_end(_ZStreamWriteRamCtx_t *const UNUSED(ctx))
{
    return NoError;
}

ZWEXPORT_PRIVATE const _ZStreamWriter_t *_zstream_write_file(void);
ZWEXPORT_PRIVATE ZWError _zstream_write_file_init(_ZStreamWriteFileCtx_t *const ctx, const ZWLog log,const ZW_FILE_HANDLE fd);
ZWEXPORT_PRIVATE ZWError _zstream_write_file_end(_ZStreamWriteFileCtx_t *const ctx);
static inline void _zstream_write_file_free(_ZStreamWriteFileCtx_t *const ctx)
{
    _zbyte_data_free(&ctx->buffering.data);
}

ZWEXPORT_PRIVATE const _ZStreamRW_t *_zstream_rw_file(void);
static inline ZWError _zstream_rw_file_init(_ZStreamRWFileCtx_t *const ctx, const ZWLog log, const ZW_FILE_HANDLE fd)
{
    ctx->offset = 0;
    return _zstream_write_file_init(&ctx->write, log, fd);
}
static inline void _zstream_rw_file_free(_ZStreamRWFileCtx_t *const ctx)
{
    return _zstream_write_file_free(&ctx->write);
}
static inline ZWError _zstream_rw_file_end(_ZStreamRWFileCtx_t *const ctx)
{
    return _zstream_write_file_end(&ctx->write);
}
static inline ZWLog _zstream_rw_get_log(const _ZStreamRWFileCtx_t *const ctx)
{
    return ctx->write.ctx_common.log;
}

ZWEXPORT_PRIVATE const _ZStreamRW_t *_zstream_rw_ram(void);
ZWEXPORT_PRIVATE void _zstream_rw_ram_init(_ZStreamRWRamCtx_t *const ctx, const ZWLog log, const size_t block_size);
static inline void _zstream_rw_ram_result(_ZStreamRWRamCtx_t *const ctx, _ZByteData_t *const data)
{
    return _zstream_write_ram_result(&ctx->write, data);
}
static inline void _zstream_rw_ram_free(_ZStreamRWRamCtx_t *const ctx)
{
    return _zstream_write_ram_free(&ctx->write);
}
static inline ZWError _zstream_rw_ram_end(_ZStreamRWRamCtx_t *const ctx)
{
    return _zstream_write_ram_end(&ctx->write);
}

ZWEXPORT_PRIVATE const _ZStreamHttpWrite_t *_zstream_http_write_ram(void);
ZWEXPORT_PRIVATE void _zstream_http_write_ram_init(_ZStreamHttpWriteRamCtx_t *const ctx, const ZWLog log, const size_t block_size);
ZWEXPORT_PRIVATE void _zstream_http_write_ram_free(_ZStreamHttpWriteRamCtx_t *const ctx);
ZWEXPORT_PRIVATE void _zstream_http_write_ram_free_content(_ZStreamHttpWriteContent_t *const content);
ZWEXPORT_PRIVATE void _zstream_http_write_ram_result(_ZStreamHttpWriteRamCtx_t *const ctx, _ZStreamHttpWriteRamResult_t *const result);
static inline ZWError _zstream_http_write_ram_end(_ZStreamHttpWriteRamCtx_t *const ctx)
{
    return _zstream_write_ram_end(&ctx->write);
}

#if defined(__ESP32__)
ZWEXPORT_PRIVATE const _ZStreamHttpWrite_t *_zstream_http_write_esp(void);
ZWEXPORT_PRIVATE void _zstream_http_write_esp_init(_ZStreamHttpWriteEspCtx_t *const ctx, const ZWLog log, httpd_req_t *const req, ZWBYTE *const buffer, const size_t length);
ZWEXPORT_PRIVATE void _zstream_http_write_esp_free(_ZStreamHttpWriteEspCtx_t *const ctx);
ZWEXPORT_PRIVATE ZWError _zstream_http_write_esp_end(_ZStreamHttpWriteEspCtx_t *const ctx);
#endif

ZWEXPORT_PRIVATE const _ZStreamReader_t *_zstream_reader_ram(void);
ZWEXPORT_PRIVATE void _zstream_reader_ram_init(_ZStreamCtxReaderRam_t *const ctx, const ZWLog log, const _ZByteData_t *const data);
static inline void _zstream_reader_ram_free(const _ZStreamCtxReaderRam_t *const UNUSED(ctx))
{
}

ZWEXPORT_PRIVATE const _ZStreamReader_t *_zstream_reader_file(void);
ZWEXPORT_PRIVATE void _zstream_reader_file_init(_ZStreamCtxReaderFile_t *const ctx, const ZWLog log, const ZW_FILE_HANDLE fd, const size_t n);
static inline void _zstream_reader_file_free(const _ZStreamCtxReaderFile_t *const UNUSED(ctx))
{
}
static inline ZW_FILE_HANDLE _zstream_reader_get_fd(const _ZStreamCtxReaderFile_t *const ctx)
{
    return ctx->fd;
}
static inline ZWLog _zstream_reader_get_log(const _ZStreamCtxReaderFile_t *const ctx)
{
    return ctx->ctx_common.log;
}

#ifdef __cplusplus
}
#endif

#endif//zstream_private_h
